﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GeneticAlgorythm.Algorythm
{
    public class OrderCrossover : Crossover
    {
        private PermutationChromosome _firstParentChromosome;
        private PermutationChromosome _secondParentChromosome;
        private PermutationChromosome _firstChildrenChromosome;
        private PermutationChromosome _secondChildrenChromosome;
        private int _matchSectionStart;
        private int _matchSectionEnd;
        private int _chromosomeSize;
        private bool _sectionStartAndEndAlreadySet = false;


        public OrderCrossover()
        {
        }

        public OrderCrossover(int matchSectionStart, int matchSectionEnd)
        {
            _matchSectionStart = matchSectionStart;
            _matchSectionEnd = matchSectionEnd;
            _sectionStartAndEndAlreadySet = true;
        }

        public List<Chromosome> execute(Chromosome firstParent, Chromosome secondParent)
        {
            _firstParentChromosome = (PermutationChromosome) firstParent;
            _secondParentChromosome = (PermutationChromosome) secondParent;
            _chromosomeSize = _firstParentChromosome.getSize();
            _firstChildrenChromosome = new PermutationChromosome(_chromosomeSize);
            _secondChildrenChromosome = new PermutationChromosome(_chromosomeSize);
            if(!_sectionStartAndEndAlreadySet)
            {
                generateSectionStartAndEnd();
            }

	        if(_matchSectionStart > _matchSectionEnd)
	        {
                swapInts(ref _matchSectionStart, ref _matchSectionEnd);
	        }

            int startGene = _matchSectionStart;
            int endGene = _matchSectionEnd;
	        for(int i = startGene; i <= endGene; ++i)
	        {
                _secondChildrenChromosome.setGene(i, _firstParentChromosome.getGene(i));
                _firstChildrenChromosome.setGene(i, _secondParentChromosome.getGene(i));
	        }

	        for(int i = ((endGene + 1)!=_chromosomeSize)?(endGene+1):0; i != startGene;)
	        {
		        int j = i;
                while (_secondChildrenChromosome.contains(_secondParentChromosome.getGene(j)))
                    if (!j.Equals(_chromosomeSize - 1))
                        j++;
                    else 
                        j = 0;

                _secondChildrenChromosome.setGene(i, _secondParentChromosome.getGene(j));
		        j = i;
                while (_firstChildrenChromosome.contains(_firstParentChromosome.getGene(j)))
                    if (!j.Equals(_chromosomeSize - 1))
                        j++;
                    else 
                        j = 0;
                _firstChildrenChromosome.setGene(i, _firstParentChromosome.getGene(j));

                if (!i.Equals(_chromosomeSize - 1))
                    i++;
                else
                    i = 0;
	        }

            return new List<Chromosome> { _firstChildrenChromosome, _secondChildrenChromosome };

        }

        private void swapInts(ref int start, ref int end)
        {
            int tmp = end;
            end = start;
            start = tmp;
        }

        private void generateSectionStartAndEnd()
        {
            _matchSectionStart = RandomGenerator.getInstance().generateRandomIntegerFromZeroTo(_chromosomeSize);
            _matchSectionEnd = RandomGenerator.getInstance().generateRandomIntegerFromZeroTo(_chromosomeSize);

            while (_matchSectionStart.Equals(_matchSectionEnd))
                _matchSectionEnd = RandomGenerator.getInstance().generateRandomIntegerFromZeroTo(_chromosomeSize);
        }
    }
}
